package worldofrobots;

import interfaces.MapPosition;
import worldofrobots.CandyEco;
import worldofrobots.RequiringPosition;
import worldofrobots.ReusableJoiningComp;

@SuppressWarnings("all")
public abstract class WorldEco {
  @SuppressWarnings("all")
  public interface Requires {
  }
  
  
  @SuppressWarnings("all")
  public interface Provides {
    /**
     * This can be called to access the provided port.
     * 
     */
    public String hello();
  }
  
  
  @SuppressWarnings("all")
  public interface Component extends WorldEco.Provides {
  }
  
  
  @SuppressWarnings("all")
  public interface Parts {
    /**
     * This can be called by the implementation to access the part and its provided ports.
     * It will be initialized after the required ports are initialized and before the provided ports are initialized.
     * 
     */
    public CandyEco.Component ce();
    
    /**
     * This can be called by the implementation to access the part and its provided ports.
     * It will be initialized after the required ports are initialized and before the provided ports are initialized.
     * 
     */
    public ReusableJoiningComp.Component rjc();
  }
  
  
  @SuppressWarnings("all")
  public static class ComponentImpl implements WorldEco.Component, WorldEco.Parts {
    private final WorldEco.Requires bridge;
    
    private final WorldEco implementation;
    
    public void start() {
      assert this.ce != null: "This is a bug.";
      ((CandyEco.ComponentImpl) this.ce).start();
      assert this.rjc != null: "This is a bug.";
      ((ReusableJoiningComp.ComponentImpl) this.rjc).start();
      this.implementation.start();
      this.implementation.started = true;
      
    }
    
    protected void initParts() {
      assert this.ce == null: "This is a bug.";
      assert this.implem_ce == null: "This is a bug.";
      this.implem_ce = this.implementation.make_ce();
      if (this.implem_ce == null) {
      	throw new RuntimeException("make_ce() in worldofrobots.WorldEco should not return null.");
      }
      this.ce = this.implem_ce._newComponent(new BridgeImpl_ce(), false);
      assert this.rjc == null: "This is a bug.";
      assert this.implem_rjc == null: "This is a bug.";
      this.implem_rjc = this.implementation.make_rjc();
      if (this.implem_rjc == null) {
      	throw new RuntimeException("make_rjc() in worldofrobots.WorldEco should not return null.");
      }
      this.rjc = this.implem_rjc._newComponent(new BridgeImpl_rjc(), false);
      
    }
    
    protected void initProvidedPorts() {
      assert this.hello == null: "This is a bug.";
      this.hello = this.implementation.make_hello();
      if (this.hello == null) {
      	throw new RuntimeException("make_hello() in worldofrobots.WorldEco should not return null.");
      }
      
    }
    
    public ComponentImpl(final WorldEco implem, final WorldEco.Requires b, final boolean doInits) {
      this.bridge = b;
      this.implementation = implem;
      
      assert implem.selfComponent == null: "This is a bug.";
      implem.selfComponent = this;
      
      // prevent them to be called twice if we are in
      // a specialized component: only the last of the
      // hierarchy will call them after everything is initialised
      if (doInits) {
      	initParts();
      	initProvidedPorts();
      }
      
    }
    
    private String hello;
    
    public final String hello() {
      return this.hello;
    }
    
    private CandyEco.Component ce;
    
    private CandyEco implem_ce;
    
    @SuppressWarnings("all")
    private final class BridgeImpl_ce implements CandyEco.Requires {
    }
    
    
    public final CandyEco.Component ce() {
      return this.ce;
    }
    
    private ReusableJoiningComp.Component rjc;
    
    private ReusableJoiningComp implem_rjc;
    
    @SuppressWarnings("all")
    private final class BridgeImpl_rjc implements ReusableJoiningComp.Requires {
      public final MapPosition allPositions() {
        return WorldEco.ComponentImpl.this.ce.allPositions();
      }
    }
    
    
    public final ReusableJoiningComp.Component rjc() {
      return this.rjc;
    }
  }
  
  
  @SuppressWarnings("all")
  public abstract static class Robots {
    @SuppressWarnings("all")
    public interface Requires {
    }
    
    
    @SuppressWarnings("all")
    public interface Provides {
      /**
       * This can be called to access the provided port.
       * 
       */
      public String status();
    }
    
    
    @SuppressWarnings("all")
    public interface Component extends WorldEco.Robots.Provides {
    }
    
    
    @SuppressWarnings("all")
    public interface Parts {
      /**
       * This can be called by the implementation to access the part and its provided ports.
       * It will be initialized after the required ports are initialized and before the provided ports are initialized.
       * 
       */
      public ReusableJoiningComp.JoiningEntity.Component je();
      
      /**
       * This can be called by the implementation to access the part and its provided ports.
       * It will be initialized after the required ports are initialized and before the provided ports are initialized.
       * 
       */
      public RequiringPosition.Component rp();
    }
    
    
    @SuppressWarnings("all")
    public static class ComponentImpl implements WorldEco.Robots.Component, WorldEco.Robots.Parts {
      private final WorldEco.Robots.Requires bridge;
      
      private final WorldEco.Robots implementation;
      
      public void start() {
        assert this.je != null: "This is a bug.";
        ((ReusableJoiningComp.JoiningEntity.ComponentImpl) this.je).start();
        assert this.rp != null: "This is a bug.";
        ((RequiringPosition.ComponentImpl) this.rp).start();
        this.implementation.start();
        this.implementation.started = true;
        
      }
      
      protected void initParts() {
        assert this.je == null: "This is a bug.";
        assert this.implementation.use_je != null: "This is a bug.";
        this.je = this.implementation.use_je._newComponent(new BridgeImpl_rjc_je(), false);
        assert this.rp == null: "This is a bug.";
        assert this.implem_rp == null: "This is a bug.";
        this.implem_rp = this.implementation.make_rp();
        if (this.implem_rp == null) {
        	throw new RuntimeException("make_rp() in worldofrobots.WorldEco$Robots should not return null.");
        }
        this.rp = this.implem_rp._newComponent(new BridgeImpl_rp(), false);
        
      }
      
      protected void initProvidedPorts() {
        assert this.status == null: "This is a bug.";
        this.status = this.implementation.make_status();
        if (this.status == null) {
        	throw new RuntimeException("make_status() in worldofrobots.WorldEco$Robots should not return null.");
        }
        
      }
      
      public ComponentImpl(final WorldEco.Robots implem, final WorldEco.Robots.Requires b, final boolean doInits) {
        this.bridge = b;
        this.implementation = implem;
        
        assert implem.selfComponent == null: "This is a bug.";
        implem.selfComponent = this;
        
        // prevent them to be called twice if we are in
        // a specialized component: only the last of the
        // hierarchy will call them after everything is initialised
        if (doInits) {
        	initParts();
        	initProvidedPorts();
        }
        
      }
      
      private String status;
      
      public final String status() {
        return this.status;
      }
      
      private ReusableJoiningComp.JoiningEntity.Component je;
      
      @SuppressWarnings("all")
      private final class BridgeImpl_rjc_je implements ReusableJoiningComp.JoiningEntity.Requires {
      }
      
      
      public final ReusableJoiningComp.JoiningEntity.Component je() {
        return this.je;
      }
      
      private RequiringPosition.Component rp;
      
      private RequiringPosition implem_rp;
      
      @SuppressWarnings("all")
      private final class BridgeImpl_rp implements RequiringPosition.Requires {
        public final MapPosition allPositions() {
          return WorldEco.Robots.ComponentImpl.this.je.positions();
        }
      }
      
      
      public final RequiringPosition.Component rp() {
        return this.rp;
      }
    }
    
    
    /**
     * Used to check that two components are not created from the same implementation,
     * that the component has been started to call requires(), provides() and parts()
     * and that the component is not started by hand.
     * 
     */
    private boolean init = false;;
    
    /**
     * Used to check that the component is not started by hand.
     */
    private boolean started = false;;
    
    private WorldEco.Robots.ComponentImpl selfComponent;
    
    /**
     * Can be overridden by the implementation.
     * It will be called automatically after the component has been instantiated.
     * 
     */
    protected void start() {
      if (!this.init || this.started) {
      	throw new RuntimeException("start() should not be called by hand: to create a new component, use newComponent().");
      }
      
    }
    
    /**
     * This can be called by the implementation to access the provided ports.
     * 
     */
    protected WorldEco.Robots.Provides provides() {
      assert this.selfComponent != null: "This is a bug.";
      if (!this.init) {
      	throw new RuntimeException("provides() can't be accessed until a component has been created from this implementation, use start() instead of the constructor if provides() is needed to initialise the component.");
      }
      return this.selfComponent;
      
    }
    
    /**
     * This should be overridden by the implementation to define the provided port.
     * This will be called once during the construction of the component to initialize the port.
     * 
     */
    protected abstract String make_status();
    
    /**
     * This can be called by the implementation to access the required ports.
     * 
     */
    protected WorldEco.Robots.Requires requires() {
      assert this.selfComponent != null: "This is a bug.";
      if (!this.init) {
      	throw new RuntimeException("requires() can't be accessed until a component has been created from this implementation, use start() instead of the constructor if requires() is needed to initialise the component.");
      }
      return this.selfComponent.bridge;
      
    }
    
    /**
     * This can be called by the implementation to access the parts and their provided ports.
     * 
     */
    protected WorldEco.Robots.Parts parts() {
      assert this.selfComponent != null: "This is a bug.";
      if (!this.init) {
      	throw new RuntimeException("parts() can't be accessed until a component has been created from this implementation, use start() instead of the constructor if parts() is needed to initialise the component.");
      }
      return this.selfComponent;
      
    }
    
    private ReusableJoiningComp.JoiningEntity use_je;
    
    /**
     * This should be overridden by the implementation to define how to create this sub-component.
     * This will be called once during the construction of the component to initialize this sub-component.
     * 
     */
    protected abstract RequiringPosition make_rp();
    
    /**
     * Not meant to be used to manually instantiate components (except for testing).
     * 
     */
    public synchronized WorldEco.Robots.Component _newComponent(final WorldEco.Robots.Requires b, final boolean start) {
      if (this.init) {
      	throw new RuntimeException("This instance of Robots has already been used to create a component, use another one.");
      }
      this.init = true;
      WorldEco.Robots.ComponentImpl comp = new WorldEco.Robots.ComponentImpl(this, b, true);
      if (start) {
      	comp.start();
      }
      return comp;
      
    }
    
    private WorldEco.ComponentImpl ecosystemComponent;
    
    /**
     * This can be called by the species implementation to access the provided ports of its ecosystem.
     * 
     */
    protected WorldEco.Provides eco_provides() {
      assert this.ecosystemComponent != null: "This is a bug.";
      return this.ecosystemComponent;
      
    }
    
    /**
     * This can be called by the species implementation to access the required ports of its ecosystem.
     * 
     */
    protected WorldEco.Requires eco_requires() {
      assert this.ecosystemComponent != null: "This is a bug.";
      return this.ecosystemComponent.bridge;
      
    }
    
    /**
     * This can be called by the species implementation to access the parts of its ecosystem and their provided ports.
     * 
     */
    protected WorldEco.Parts eco_parts() {
      assert this.ecosystemComponent != null: "This is a bug.";
      return this.ecosystemComponent;
      
    }
  }
  
  
  /**
   * Used to check that two components are not created from the same implementation,
   * that the component has been started to call requires(), provides() and parts()
   * and that the component is not started by hand.
   * 
   */
  private boolean init = false;;
  
  /**
   * Used to check that the component is not started by hand.
   */
  private boolean started = false;;
  
  private WorldEco.ComponentImpl selfComponent;
  
  /**
   * Can be overridden by the implementation.
   * It will be called automatically after the component has been instantiated.
   * 
   */
  protected void start() {
    if (!this.init || this.started) {
    	throw new RuntimeException("start() should not be called by hand: to create a new component, use newComponent().");
    }
    
  }
  
  /**
   * This can be called by the implementation to access the provided ports.
   * 
   */
  protected WorldEco.Provides provides() {
    assert this.selfComponent != null: "This is a bug.";
    if (!this.init) {
    	throw new RuntimeException("provides() can't be accessed until a component has been created from this implementation, use start() instead of the constructor if provides() is needed to initialise the component.");
    }
    return this.selfComponent;
    
  }
  
  /**
   * This should be overridden by the implementation to define the provided port.
   * This will be called once during the construction of the component to initialize the port.
   * 
   */
  protected abstract String make_hello();
  
  /**
   * This can be called by the implementation to access the required ports.
   * 
   */
  protected WorldEco.Requires requires() {
    assert this.selfComponent != null: "This is a bug.";
    if (!this.init) {
    	throw new RuntimeException("requires() can't be accessed until a component has been created from this implementation, use start() instead of the constructor if requires() is needed to initialise the component.");
    }
    return this.selfComponent.bridge;
    
  }
  
  /**
   * This can be called by the implementation to access the parts and their provided ports.
   * 
   */
  protected WorldEco.Parts parts() {
    assert this.selfComponent != null: "This is a bug.";
    if (!this.init) {
    	throw new RuntimeException("parts() can't be accessed until a component has been created from this implementation, use start() instead of the constructor if parts() is needed to initialise the component.");
    }
    return this.selfComponent;
    
  }
  
  /**
   * This should be overridden by the implementation to define how to create this sub-component.
   * This will be called once during the construction of the component to initialize this sub-component.
   * 
   */
  protected abstract CandyEco make_ce();
  
  /**
   * This should be overridden by the implementation to define how to create this sub-component.
   * This will be called once during the construction of the component to initialize this sub-component.
   * 
   */
  protected abstract ReusableJoiningComp make_rjc();
  
  /**
   * Not meant to be used to manually instantiate components (except for testing).
   * 
   */
  public synchronized WorldEco.Component _newComponent(final WorldEco.Requires b, final boolean start) {
    if (this.init) {
    	throw new RuntimeException("This instance of WorldEco has already been used to create a component, use another one.");
    }
    this.init = true;
    WorldEco.ComponentImpl comp = new WorldEco.ComponentImpl(this, b, true);
    if (start) {
    	comp.start();
    }
    return comp;
    
  }
  
  /**
   * This should be overridden by the implementation to instantiate the implementation of the species.
   * 
   */
  protected abstract WorldEco.Robots make_Robots(final String id);
  
  /**
   * Do not call, used by generated code.
   * 
   */
  public WorldEco.Robots _createImplementationOfRobots(final String id) {
    WorldEco.Robots implem = make_Robots(id);
    if (implem == null) {
    	throw new RuntimeException("make_Robots() in worldofrobots.WorldEco should not return null.");
    }
    assert implem.ecosystemComponent == null: "This is a bug.";
    assert this.selfComponent != null: "This is a bug.";
    implem.ecosystemComponent = this.selfComponent;
    assert this.selfComponent.implem_rjc != null: "This is a bug.";
    assert implem.use_je == null: "This is a bug.";
    implem.use_je = this.selfComponent.implem_rjc._createImplementationOfJoiningEntity();
    return implem;
  }
  
  /**
   * This can be called to create an instance of the species from inside the implementation of the ecosystem.
   * 
   */
  protected WorldEco.Robots.Component newRobots(final String id) {
    WorldEco.Robots implem = _createImplementationOfRobots(id);
    return implem._newComponent(new WorldEco.Robots.Requires() {},true);
  }
  
  /**
   * Use to instantiate a component from this implementation.
   * 
   */
  public WorldEco.Component newComponent() {
    return this._newComponent(new WorldEco.Requires() {}, true);
  }
}
